import axios from "@/axios";
import dayjs from "dayjs"
import customParseFormat from "dayjs/plugin/customParseFormat"
// import { useStore } from "vuex";
import { useUserStore } from '@/store/modules/user';

// import _store from "@/store"
import { trim } from "xe-utils";
// @ts-ignore
import { sm2 } from 'sm-crypto';
import {ElMessage} from "element-plus";

dayjs.extend(customParseFormat)

  ////////////////////////////////时间///////////////////////////
  /**
   * 时间字符串解析为date
   * @param dateStr 时间字符串
   */
  ; (Date as any).parseDate = function (dateStr: any) {
    if (!dateStr) {
      return null;
    }
    if (dateStr instanceof Date) {
      //本身就是date类型
      return dateStr;
    }
    let d = dayjs(dateStr, ["YYYYMMDDHHmmss", "YYYYMMDDHHmmssSSS","YYYYMMDD", "YYMMDD", "YYYY-MM-DD HH:mm:ss.SSS", "YYYY-MM-DD",
      "YYYY年MM月DD日HH时mm分ss秒", "YYYY年MM月DD日", "YYYY/MM/DD","YYYY/M/D"])
    return d.toDate();
  }
  /**
   * 时间对象的格式化
   */
  ; (Date as any).prototype.format = function (format: any) {
    const o = {
      "M+": this.getMonth() + 1, // month
      "D+": this.getDate(), // day
      "H+": this.getHours(), // hour
      "m+": this.getMinutes(), // minute
      "s+": this.getSeconds(), // second
      "q+": Math.floor((this.getMonth() + 3) / 3), // quarter
      "S+": this.getMilliseconds()
    };

    if (/(Y+)/.test(format)) {
      format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    }

    for (const k in o) {
      if (new RegExp("(" + k + ")").test(format)) {
        format = format.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
      }
    }
    return format;
  };
/**
 * 时间格式化
 */
export function dateFormat(dateStr: any, fmt: any) {
  const d = (Date as any).parseDate(dateStr);
  if (d) {
    if (fmt === 'date') {
      //为时间对象时，传输中转为14位时间
      fmt = 'yyyyMMddHHmmss';
    }
    return d.format(fmt);
  } else {
    return "";
  }
}

/**
 * dayjs的加减方法调用
 * @param obj
 */
export function dayjsMethod(obj: any) {
  return dayjs()[obj.method](obj.value, obj.dw).format("YYYYMMDDHHmmss");
}

/**
 * 暂停指定时长
 * @param ms 暂时时间
 */
export function delay(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}
/**
 * 生成全球唯一键
 */
export const uuid = () => {
  const temp_url = URL.createObjectURL(new Blob());
  const uuid = temp_url.toString();
  URL.revokeObjectURL(temp_url); //释放这个url
  return uuid.substring(uuid.lastIndexOf("/") + 1).replaceAll("-","");
};
////////////////////////////////时间///////////////////////////
/**
 * json字符串格式化
 * @param text_value 待格式化字符串
 * @returns {string|boolean}
 */
export function jsonFormat(text_value: any) {
  if (isEmpty(text_value)) {
    alert("不能为空");
    return false;
  }
  if (typeof text_value !== 'string') {
    text_value = JSON.stringify(text_value);
  }
  text_value = trim(text_value);
  if (text_value.indexOf("\n") > 0 || (!text_value.startsWith("{") && !text_value.startsWith("["))) {
    //存在换行，不进行格式化
    return text_value
  }
  //结果
  let res = "";
  let i = 0, j = 0, k = 0, ii, ele;
  for (; i < text_value.length; i++) {
    //k:缩进，j:""个数
    ele = text_value.charAt(i);
    if (j % 2 === 0 && (ele === "}" || ele === "]")) {
      k--;
      for (ii = 0; ii < k; ii++) {
        ele = "  " + ele;
      }
      ele = "\n" + ele;
    } else if (j % 2 === 0 && (ele === "{" || ele === "[")) {
      ele += "\n";
      k++;
      for (ii = 0; ii < k; ii++) ele += "  ";
    } else if (j % 2 === 0 && ele === ",") {
      ele += "\n";
      for (ii = 0; ii < k; ii++) {
        ele += "  ";
      }
    } else if (ele === "\"") {
      j++;
    }
    res += ele;
  }
  return res
}

/**
 * 解析json字符串，兼容注释和key不带引号的场景
 * @param jsonString 待解析字符串
 */
export function parseJson(jsonString:any){
  // 移除单行注释
  jsonString = jsonString.replace(/\/\/.*/g, '');
  // 移除多行注释
  jsonString = jsonString.replace(/\/\*[\s\S]*?\*\//g, '');
  // 将没有引号的键转换为带有引号的键
  const jsonWithQuotedKeys = jsonString.replace(/\b([a-zA-Z0-9_]+)\s*:/g, '"$1":');
  return JSON.parse(jsonWithQuotedKeys);
}

/**
 * 是否有权限
 * @param auth 权限码
 * @returns {*} 权限对象，为空则没权限
 */
export const hasAuth = (auth: any) => {
  const userStore = useUserStore();
  return userStore.getUser.qxMap&&userStore.getUser.qxMap[auth]
}

////////////////////////////////字典///////////////////////////
/**
 * 字典缓存
 * @type {{}}
 */
const globalData = {
  zdListCache: {}
};

/**
 * 获取字典项
 * @param zdObj 字典类别等信息对象
 * @param cache 是否缓存，默认采用缓存
 * @returns {Promise<unknown>} 字典对象-异步
 */
export async function zdObj(zdObj: any, cache?: any,) {
  let obj = null;
  await zdObjG(globalData, zdObj, cache).then(function (data:any){
    obj = data;
  }).catch(()=>{
    ElMessage.error("获取数据失败")
  });
  if(obj === null){
    obj = zdObj;
    obj.idx = 0;
    if(!obj.mc){
      obj.mc = obj.dm;
    }
    if(!obj.dm){
      obj.dm = obj.mc;
    }
  }
  return obj;
}

/**
 * 获取字典列表
 * @param zdlb 字典类别
 * @returns {Promise<unknown>} 字典列表-异步
 */
export async function zdList(zdlb: any) {
  let list = null;
  await zdListG(globalData, { zdlb: zdlb }).then(function (data:any){
    list = data;
  }).catch((e:any)=>{
    ElMessage.error("获取数据失败："+e)
  });
  return list;
}
/**
 * 获取字典树
 * @param zdlb 字典类别
 * @returns {Promise<unknown>} 字典树-异步
 */
export async function zdTree(zdlb: any) {
  let tree = null;
  await zdTreeG(globalData, zdlb).then(function (data:any){
    tree = data;
  }).catch((e)=>{
    ElMessage.error("获取数据失败："+e)
  });
  return tree;
}
/**
 * 获取字典树
 * @param globalData 全局变量
 * @param zdlb 字典类别
 */
function zdTreeG(globalData: any, zdlb: any) {
  return new Promise((resolve, reject) => {
    const zdListCache = globalData.zdListCache;
    if (zdListCache[zdlb + "tree"] == null) {
      axios.post({
        //数据对象
        "sys": {
          authCode: "QTQX_ZDGL",
          "cllx": "zdTree",
        },
        "yobj": {
          "zdlb": zdlb
        },
      }, { ctdy: false, tloading: false }).then(function (res) {
        zdListCache[zdlb + "_tree"] = res.data;
        resolve(res.data);
      }).catch(function (rep) {
        reject(rep);
      })
    } else {
      resolve(zdListCache[zdlb + "_tree"]);
    }
  });
}
/**
 * 获取字典列表
 * @param globalData 全局变量
 * @param zdlb 字典类别
 */
function zdListG(globalData: any, zdObj: any) {
  return new Promise((resolve, reject) => {
    const zdListCache = globalData.zdListCache;
    if (zdListCache[zdObj.zdlb + "_nocache"]) {
      //不支持获取列表
      reject("该字典类别不支持获取字典列表："+zdObj.zdlb);
    } else if (zdListCache[zdObj.zdlb] == null) {
      axios.post({
        //数据对象
        "sys": {
          authCode: "QTQX_ZDGL",
          "cllx": "zdList",
        },
        "yobj": { ...zdObj }
      }, { ctdy: false, tloading: false }).then(function (res) {
        if (res.status && res.data) {
          let list = []
          for (const i in res.data) {
            res.data[i].dm = res.data[i].dm.toString();
            list.push(res.data[i])
          }
          zdListCache[zdObj.zdlb] = list;
          resolve(list);
        } else {
          //不支持获取列表
          zdListCache[zdObj.zdlb + "_nocache"] = true;
          zdListCache[zdObj.zdlb] = [];
          reject("该字典类别不支持获取字典列表："+zdObj.zdlb);
        }
      }).catch(function (rep) {
        reject(rep);
      })
    } else {
      resolve(zdListCache[zdObj.zdlb]);
    }
  });
}
/**
 * 获取字典对象
 * @param globalData 全局变量
 * @param zdObj 字典对象
 * @param cache 是否缓存
 */
function zdObjG(globalData: any, zdObj: any, cache: any) {
  return new Promise((resolve, reject) => {
    const zdListCache = globalData.zdListCache;
    const zdlb = zdObj.zdlb;
    const dm = zdObj.dm;
    const mc = zdObj.mc;
    let obj: any = null;
    if (zdlb) {
      if (cache === undefined) {
        //默认走缓存
        cache = true;
      }
      if (cache) {
        zdListG(globalData, zdObj).then(function (zl: any) {
          let i;
          //获取了字典列表
          if (dm) {
            for (i in zl as any) {
              if (zl[i].dm == dm) {
                obj = zl[i];
                obj.idx = i;
                break;
              }
            }
            if (!obj) {
              obj = {
                dm: dm,
                mc: dm
              }
            }
          } else if (mc) {
            for (i in zl) {
              if (zl[i].mc == mc) {
                obj = zl[i];
                obj.idx = i;
                break;
              }
            }
            if (!obj) {
              obj = {
                dm: mc,
                mc: mc
              }
            }
          }
          resolve(obj);
        }).catch(function () {
          if (zdListCache[zdlb][dm]) {
            //该字典的具体字典项已经缓存。
            obj = zdListCache[zdlb][dm];
            resolve(obj);
          } else if (zdListCache[zdlb][mc]) {
            //该字典的具体字典项已经缓存。
            obj = zdListCache[zdlb][mc];
            resolve(obj);
          } else {
            postZdObj(globalData, {
              sys: {
              },
              yobj: zdObj
            }).then((data) => {
              resolve(data);
            }).catch((e) => {
              reject("获取字典异常："+e);
            })
          }
        });
      } else {
        postZdObj(globalData, {
          sys: {
            //不走缓存
            dataCache: false
          },
          yobj: zdObj
        }).then((data) => {
          resolve(data);
        }).catch((e) => {
          reject("获取字典异常："+e);
        })
      }
    } else {
      reject("获取字典对象异常，字典类别为空");
    }
  });
}
function postZdObj(globalData: any, data: any) {
  const zdListCache = globalData.zdListCache;
  return new Promise(function (resolve, reject) {
    data.sys.authCode = "QTQX_ZDGL";
    data.sys.cllx = "zdObj";
    axios.post(data, { ctdy: false, tloading: false }).then(function (res) {
      let obj
      let dm
      let mc
      if (res.status) {
        const zd = res.data;
        dm = zd.dm
        mc = zd.mc
        zdListCache[data.yobj.zdlb][zd.dm] = zd;
        zdListCache[data.yobj.zdlb][zd.mc] = zd;
        obj = zd;
      } else if (dm) {
        obj = {
          "dm": dm,
          "mc": dm
        };
        zdListCache[data.yobj.zdlb][dm] = obj;
      } else if (mc) {
        obj = {
          "dm": mc,
          "mc": mc
        };
        zdListCache[data.yobj.zdlb][mc] = obj;
      }
      resolve(obj);
    }).catch(function (e) {
      reject("字典请求异常："+data.yobj.zdlb+e)
    })
  })
}

/**
 * 获取字典名称
 * @param zdlb 字典类别
 * @param dm 字典代码
 */
export async function zdMcByDm(zdlb: any, dm: any) {
  let res = await zdObj({
    zdlb: zdlb,
    dm: dm
  })
  return res.mc;
}
/**
 * 获取字典名称多个
 * @param zdlb 字典类别
 * @param dm 字典代码
 */
export async function zdMcByDmMore(zdlb: any, dm: any) {
  if (dm) {
    let mcs = "";
    const dms = (dm + "").split(",");
    for (let i = 0; i < dms.length; i++) {
      if (isEmpty(dms[i])) {
        mcs += "、";
        continue;
      }
      mcs += "、" + await zdMcByDm(zdlb, dms[i]);
    }
    return mcs.substring(1);
  } else {
    return dm;
  }
}
/**
 * 获取字典名称
 * @param zdlb 字典类别
 * @param mc 字典名称
 */
export async function zdDmByMc(zdlb: any, mc: any) {
  let obj = await zdObj(globalData, {
    zdlb: zdlb,
    mc: mc
  });
  return obj.mc;
}
/**
 * 获取字典名称
 * @param globalData 公共变量
 * @param zdlb 字典类别
 * @param mc 字典名称
 */
export async function zdIdxByMc(globalData: any, zdlb: any, mc: any) {
    let obj = await zdObj(globalData, {
      zdlb: zdlb,
      mc: mc
    });
    return obj.idx;
}
////////////////////////////////字典///////////////////////////

/**
 * 判断字符串是否为空
 * @param str 要判断的字符串
 * @returns 空：true，非空：false
 */
export function isEmpty(str: any) {
  return str === null || str === undefined || str === "";
}
/**
 * 是否是非负整数
 * @param str
 * @returns 非负整数：true，否则：false
 */
export function isNumber(str: any) {
  return (/^(\+|-)?\d+$/.test(str)) && str >= 0;
}

/**
 * 基于jsonpath给对象设置值
 * @param obj 对象
 * @param path 路径
 * @param value 值
 * @returns {boolean}
 */
export function setByPath(obj: any, path: any, value: any) {
  //将传入的对象路径字符串拆分为数组
  const pathList = path.split('.');
  if (!obj) {
    obj = {}
  }
  for (let i = 0; i < pathList.length; i++) {
    const key = pathList[i];
    if (i === pathList.length - 1) {
      obj[key] = value;
      return true;
    }
    if (!obj[key]) {
      obj[key] = {}
    }
    obj = obj[key];
  }
}
/**
 * 基于jsonpath给对象设置值
 * @param obj 对象
 * @param path 路径
 */
export function getByPath(obj: any, path: any) {
  //将传入的对象路径字符串拆分为数组
  const pathList = path.split('.');
  if (!obj) {
    return null;
  }
  for (let i = 0; i < pathList.length; i++) {
    const key = pathList[i];
    if (i === pathList.length - 1) {
      return obj[key];
    }
    if (!obj[key]) {
      return null
    }
    obj = obj[key];
  }
}

/**
 * 基于jsonpath进行属性拷贝
 * @param target 目标对象
 * @param source 来源对象
 * @param path 路径
 */
export function copyByPath(target: any, source: any, path: any) {
  setByPath(target, path, getByPath(source, path))
}

/**
 * 基于jsonpath进行属性拷贝
 * @param target 目标对象
 * @param source 来源对象
 * @param map 路径映射集合
 */
export function copyByPathMap(target: any, source: any, map: any) {
  if (map) {
    let deleteKeys = [];
    for (const key in map) {
      if (map[key] === '<delete') {
        deleteKeys.push(key);
      } else {
        setByPath(target, key, getByPath(source, map[key]))
      }
    }
    //最后进行删除操作
    for (const key in deleteKeys) {
      delete target[deleteKeys[key]]
    }
  }
}

/**
 * 深拷贝
 * @param obj
 */
export function clone(obj: any) {
  return obj?JSON.parse(JSON.stringify(obj)):obj;
}

/**
 * 对象深拷贝合并
 * @param target
 * @param sources
 * @returns {any}
 */
export function assignDeep(target: any, ...sources: any) {
  // 1. 参数校验
  if (target == null) {
    throw new TypeError('Cannot convert undefined or null to object');
  }

  // 2. 如果是基本类型数据转为包装对象
  let result = Object(target);

  // 3. 缓存已拷贝过的对象，解决引用关系丢失问题
  if (!result['__hash__']) {
    result['__hash__'] = new WeakMap();
  }
  let hash = result['__hash__'];

  sources.forEach((v: any) => {
    // 4. 如果是基本类型数据转为对象类型
    let source = Object(v);
    // 5. 遍历原对象属性，基本类型则值拷贝，对象类型则递归遍历
    Reflect.ownKeys(source).forEach(key => {
      // 6. 跳过自有的不可枚举的属性
      if (!Object.getOwnPropertyDescriptor(source, key)!.enumerable) {
        return;
      }
      if (typeof source[key] === 'object' && source[key] !== null) {
        // 7. 属性的冲突处理和拷贝处理
        let isPropertyDone = false;
        if (!result[key] || !(typeof result[key] === 'object')
          || Array.isArray(result[key]) !== Array.isArray(source[key])) {
          // 当 target 没有该属性，或者属性类型和 source 不一致时，直接整个覆盖
          if (hash.get(source[key])) {
            result[key] = hash.get(source[key]);
            isPropertyDone = true;
          } else {
            result[key] = Array.isArray(source[key]) ? [] : {};
            hash.set(source[key], result[key]);
          }
        }
        if (!isPropertyDone) {
          result[key]['__hash__'] = hash;
          assignDeep(result[key], source[key]);
        }
      } else {
        Object.assign(result, { [key]: source[key] });
      }
    });
  });

  delete result['__hash__'];
  return result;
}
//生成密钥
let keypair = sm2.generateKeyPairHex()
// 私钥
export const myPrivateKey = keypair.privateKey
// 公钥
export const myPublicKey = keypair.publicKey
/**
 * sm2加密
 * @param msgString 待加密串
 * @param publicKey2 公钥
 */
export function sm2Encrypt(msgString: any, publicKey2: string) {
  let msg = msgString
  if (typeof msgString !== 'string') {
    msg = JSON.stringify(msgString)
  }
  // 1 - C1C3C2；	0 - C1C2C3；	默认为1
  let cipherMode = 1
  // 加密结果
  let encryptData = sm2.doEncrypt(msg, publicKey2, cipherMode)
  // 加密后的密文前需要添加04，后端才能正常解密 (不添加04，后端处理也可以)
  let encrypt = '04' + encryptData
  return encrypt
}

/**
 * sm2解密
 * @param enStr 待解密字符串
 * @param privateKey1 私钥
 */
export function sm2DecryptStr(enStr: any, privateKey1: string) {
  // 1 - C1C3C2；	0 - C1C2C3；  默认为1
  let cipherMode = 1
  let enval = enStr.substring(2)
  // 解密结果
  let doDecrypt = sm2.doDecrypt(enval, privateKey1, cipherMode)
  // 解密后类型转换
  let objData = JSON.parse(doDecrypt)
  return objData
}

export default {
  dateFormat,
  isEmpty,
  isNumber,
  DATE_FORMAT_19: "yyyy-MM-dd HH:mm:ss",
  DATE_FORMAT_14: "yyyyMMddHHmmss",
  DATE_FORMAT_10: "yyyy-MM-dd",
  DATE_FORMAT_8: "yyyyMMdd",
}
